#include<mainwindow.h>
#include<astar.h>
#include<cmath>
#include<QFile>
#include<QTextStream>
#include<QIODevice>
#include<QFileInfo>

Astar::Astar(const QString &text, QWidget *parent,int width,int height) : MapLabel(text,parent,width,height){
    //qDebug()<<w<<h;
    issolved=false;
}
void Astar::runAstar(){
    if(issolved) return;

    openlist.clear();

    if(start.isNull() or end.isNull()){
        qDebug()<<"fuck";
        QMessageBox::information(this,"Caution","Please set a start point and a destination point",QMessageBox::Ok);
        return;
    }

    startx=start.x();
    starty=start.y();
    endx=end.x();
    endy=end.y();

    for(int i=1; i<=h; i++){
        for(int j=1; j<=w; j++){

            anode[i][j].g=0;
            anode[i][j].h=abs(abs(i-endx)-abs(j-endy))*10+(abs(i-endx)>abs(j-endy)?abs(j-endy)*14:abs(i-endx)*14)-14;
            //anode[i][j].h=(abs(i-endx)+abs(j-endy))*10;
            anode[i][j].cost=anode[i][j].h+anode[i][j].g;
            anode[i][j].x=i;
            anode[i][j].y=j;
            anode[i][j].isInOpenList=false;
            if(status[i][j]==0){
                anode[i][j].isClosed=false;
            }
            if(status[i][j]==1 or status[i][j]==2){
                anode[i][j].isClosed=true;
            }
        }
    }

    /*
    QFile file("test.txt");
    QFileInfo in(file);
    file.open(QIODevice::ReadWrite | QIODevice::Text);
    if(file.isOpen()) qDebug()<<in.absolutePath();
    QTextStream stream(&file);
    for(int i=1; i<=h; i++){
        for(int j=1; j<=w; j++) stream<<status[i][j]<<anode[i][j].isClosed<<" ";
        stream<<endl;
    }
    qDebug()<<startx;
    qDebug()<<starty;
    qDebug()<<endx;
    qDebug()<<endy;
    file.close();
    */




    Astarnode current;
    //int currentcost=0;
    int optrx;
    int optry;
    current=anode[startx][starty];
    while(1){

        for(int i=1; i<=4; i++){
            optrx=current.x+(i>=3?1:-1);
            optry=current.y+pow(-1,i);
            if(optrx<=0 or optrx>h or optry<=0 or optry>w) continue;
            if(anode[current.x][optry].isClosed and anode[optrx][current.y].isClosed) continue;
            if(anode[optrx][optry].isClosed) continue;
            if(anode[optrx][optry].g==0){
                anode[optrx][optry].g=current.g+14;
                anode[optrx][optry].cost+=(current.g+14);
                anode[optrx][optry].lastpoint.setX(current.x);
                anode[optrx][optry].lastpoint.setY(current.y);
                putopenlist(openlist,anode[optrx][optry]);
                anode[optrx][optry].isInOpenList=true;
            }
            else if(anode[optrx][optry].g>current.g+14 and anode[optrx][optry].isInOpenList){
                anode[optrx][optry].g=current.g+14;
                anode[optrx][optry].cost=anode[optrx][optry].g+anode[optrx][optry].h;
                anode[optrx][optry].lastpoint.setX(current.x);
                anode[optrx][optry].lastpoint.setY(current.y);
                //openlist重新排序
                resortopenlist(openlist,anode[optrx][optry]);
            }
        }

        for(int i=1; i<=4; i++){

            optrx=current.x+((i+1)%2)*(i-3);
            optry=current.y+(i%2)*(i-2);
            if(optrx<=0 or optrx>h or optry<=0 or optry>w) continue;
            if(anode[optrx][optry].isClosed) continue;
            if(anode[optrx][optry].g==0){
                anode[optrx][optry].g=current.g+10;
                anode[optrx][optry].cost=anode[optrx][optry].g+anode[optrx][optry].h;
                anode[optrx][optry].lastpoint.setX(current.x);
                anode[optrx][optry].lastpoint.setY(current.y);
                putopenlist(openlist,anode[optrx][optry]);
                anode[optrx][optry].isInOpenList=true;
            }
            else if(anode[optrx][optry].g>current.g+10 and anode[optrx][optry].isInOpenList){
                anode[optrx][optry].g=current.g+10;
                anode[optrx][optry].cost=anode[optrx][optry].g+anode[optrx][optry].h;
                anode[optrx][optry].lastpoint.setX(current.x);
                anode[optrx][optry].lastpoint.setY(current.y);
                resortopenlist(openlist,anode[optrx][optry]);
            }
        }
        if(openlist.isEmpty()){
            notfound();
            qDebug()<<"not found";
            return;
        }
        if(anode[endx][endy].isInOpenList) break;
        current=getopenlist(openlist);

    }
    issolved=true;
    shutevent=true;
    qDebug()<<"here";
    updateandpaint();
}
void Astar::updateandpaint(){
    Astarnode current=anode[endx][endy];
    if(current.lastpoint.x()==startx and current.lastpoint.y()==starty){
        QMessageBox::information(this,"啊啊啊啊啊","不要贴贴，贴贴危险",QMessageBox::Ok);
        clearways();
        return;
    }

    waypath.clear();
    while(1){
        current=anode[current.lastpoint.x()][current.lastpoint.y()];
        if(current.x==startx and current.y==starty) break;
        status[current.x][current.y]=4;
        waypath.addRoundedRect(2+(current.y-1)*24,2+(current.x-1)*24,20,20,6,6);
    }
    //setMapPath();
    QPainter painter(&mappic);
    painter.setPen(Qt::black);
    painter.setRenderHint(QPainter::Antialiasing);

    painter.setBrush(QBrush(Qt::yellow));
    painter.drawPath(waypath);
    painter.end();
    this->setPixmap(mappic);
}
void Astar::putopenlist(QList<Astarnode> &list, Astarnode data){
    if(list.isEmpty()){
        list.append(data);
        return;
    }
    else{
        for(int i=0; i<list.size(); i++){
            if(list[i].cost>data.cost){
                list.insert(i,data);
                return;
            }
        }
        list.append(data);
    }
}

Astarnode Astar::getopenlist(QList<Astarnode> &list){
    Astarnode a=list[0];
    anode[a.x][a.y].isInOpenList=false;
    list.removeFirst();
    return a;
}
void Astar::resortopenlist(QList<Astarnode> &list, Astarnode data){
    for(int i=0; i<list.size(); i++){
        if(list[i].x==data.x and list[i].y==data.y){
            list.removeAt(i);
        }
    }
    putopenlist(list,data);
}
void Astar::clearways(){
    if(!issolved) return;
    Astarnode current=anode[endx][endy];
    while(1){
        current=anode[current.lastpoint.x()][current.lastpoint.y()];
        if(current.x==startx and current.y==starty) break;
        status[current.x][current.y]=0;
    }
    //setMapPath();

    QPainter painter(&mappic);
    painter.setPen(Qt::black);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(QBrush(Qt::white));
    painter.drawPath(waypath);
    painter.end();
    this->setPixmap(mappic);

    issolved=false;
    shutevent=false;
    openlist.clear();

}
void Astar::notfound(){
    QMessageBox::information(this,"Caution","Way not found!",QMessageBox::Ok);
}
